﻿/*
  private void button1_Click(object sender, EventArgs e)
        {
            IP2Location objScan = new IP2Location();
            string ip = "125.254.131.242";
            objScan.DataPath = @"D:\我的文档\QQWry.Dat";
            objScan.IP = ip;
            string addre = objScan.IPLocation();
            string err = objScan.ErrMsg;
            MessageBox.Show(addre);
        }
 */
using System;
using System.IO;
using System.Web;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Net;
namespace WinnerCMS.Common
{
    /// <summary>
    /// 查找IP的地址
    /// </summary>
    public class IP2Location : IDisposable
    {
        #region 私有成员

        private long _firstStartIp = 0;
        private long _lastStartIp = 0;
        private FileStream _objfs = null;
        private long _startIp = 0;
        private long _endIp = 0;
        private int _countryFlag = 0;
        private long _endIpOff = 0;

        private readonly static Regex ObjRe = new Regex(@"(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))");
        #endregion

        #region 构造函数
        public IP2Location()
        {
            ErrMsg = null;
            DataPath = HttpContext.Current.Server.MapPath("~/App_Data/QQWry.Dat");
        }

        #endregion

        #region 公共属性

        /// <summary>
        /// IP数据库地址
        /// </summary>
        public string DataPath { private get; set; }

        /// <summary>
        /// 要检查的IP
        /// </summary>
        public string IP { private get; set; }

        /// <summary>
        /// 国家/区域
        /// </summary>
        public string Country { get; private set; }

        /// <summary>
        /// 网络--铁通,电信....
        /// </summary>
        public string Local { get; private set; }

        /// <summary>
        /// 错误信息
        /// </summary>
        public string ErrMsg { get; private set; }

        #endregion

        #region 搜索匹配数据
        private int QQwry()
        {
            Match objMa = ObjRe.Match(IP);
            if (objMa.Success == false)
            {
                ErrMsg = "IP格式错误";
                return 4;
            }

            long ipInt = IpToInt(IP);
            int nRet = 0;
            if (ipInt >= IpToInt("127.0.0.0") && ipInt <= IpToInt("127.255.255.255"))
            {
                Country = "本机内部环回地址";
                Local = "";
                nRet = 1;
            }
            else if ((ipInt >= IpToInt("0.0.0.0") && ipInt <= IpToInt("2.255.255.255")) || (ipInt >= IpToInt("64.0.0.0") && ipInt <= IpToInt("126.255.255.255")) || (ipInt >= IpToInt("58.0.0.0") && ipInt <= IpToInt("60.255.255.255")))
            {
                Country = "网络保留地址";
                Local = "";
                nRet = 1;
            }
            this._objfs = new FileStream(DataPath, FileMode.Open, FileAccess.Read);
            try
            {
                this._objfs.Position = 0;
                byte[] buff = new Byte[8];
                this._objfs.Read(buff, 0, 8);
                this._firstStartIp = buff[0] + buff[1] * 256 + buff[2] * 256 * 256 + buff[3] * 256 * 256 * 256;
                this._lastStartIp = buff[4] * 1 + buff[5] * 256 + buff[6] * 256 * 256 + buff[7] * 256 * 256 * 256;
                long recordCount = Convert.ToInt64((this._lastStartIp - this._firstStartIp) / 7.0);
                if (recordCount <= 1)
                {
                    Country = "数据库文件错误"; //"FileDataError";
                    this._objfs.Close();
                    return 2;
                }
                long rangE = recordCount;
                long rangB = 0;
                long recNO = 0;
                while (rangB < rangE - 1)
                {
                    recNO = ((rangE + rangB) / 2);
                    GetStartIp(recNO);
                    if (ipInt == this._startIp)
                    {
                        rangB = recNO;
                        break;
                    }
                    if (ipInt > this._startIp)
                        rangB = recNO;
                    else
                        rangE = recNO;
                }
                GetStartIp(rangB);
                GetEndIp();
                if (this._startIp <= ipInt && this._endIp >= ipInt)
                {
                    GetCountry();
                    Local = Local.Replace("（我们一定要解放台湾！！！）", "");
                }
                else
                {
                    nRet = 3;
                    Country = "未知";
                    Local = "";
                }
                this._objfs.Close();
                return nRet;
            }
            catch
            {
                return 1;
            }

        }
        #endregion

        #region IP地址转换成Int数据
        /// <summary>
        /// IP地址转换成long数据
        /// </summary>
        /// <param name="ip">IP地址</param>
        /// <returns></returns>
        public static long IpToInt(string ip)
        {
            string[] ipArr = ip.Split('.');
            if (ipArr.Length == 3)
            {
                ip = ip + ".0";
                ipArr = ip.Split('.');
            }

            long p1 = long.Parse(ipArr[0]) * 256 * 256 * 256;
            long p2 = long.Parse(ipArr[1]) * 256 * 256;
            long p3 = long.Parse(ipArr[2]) * 256;
            long p4 = long.Parse(ipArr[3]);

            return p1 + p2 + p3 + p4;
        }
        #endregion

        #region int转换成IP
        /// <summary>
        /// int转换成IP
        /// </summary>
        /// <param name="ipInt"></param>
        /// <returns></returns>
        public static string IntToIP(long ipInt)
        {
            long seg1 = (ipInt & 0xff000000) >> 24;
            if (seg1 < 0)
                seg1 += 0x100;
            long seg2 = (ipInt & 0x00ff0000) >> 16;
            if (seg2 < 0)
                seg2 += 0x100;
            long seg3 = (ipInt & 0x0000ff00) >> 8;
            if (seg3 < 0)
                seg3 += 0x100;
            long seg4 = (ipInt & 0x000000ff);
            if (seg4 < 0)
                seg4 += 0x100;
            string ip = seg1 + "." + seg2 + "." + seg3 + "." + seg4;

            return ip;
        }
        #endregion

        #region 获取起始IP范围
        /// <summary>
        /// 获取起始IP范围
        /// </summary>
        /// <param name="recNO"></param>
        /// <returns></returns>
        private long GetStartIp(long recNO)
        {
            long offSet = this._firstStartIp + recNO * 7;

            this._objfs.Position = offSet;
            byte[] buff = new Byte[7];
            this._objfs.Read(buff, 0, 7);

            this._startIp = Convert.ToInt64(buff[0]) + Convert.ToInt64(buff[1]) * 256 + Convert.ToInt64(buff[2]) * 256 * 256 + Convert.ToInt64(buff[3]) * 256 * 256 * 256;

            this._endIpOff = Convert.ToInt64(buff[4]) + Convert.ToInt64(buff[5]) * 256 + Convert.ToInt64(buff[6]) * 256 * 256;

            return this._startIp;
        }
        #endregion

        #region 获取结束IP
        /// <summary>
        /// 获取结束IP
        /// </summary>
        /// <returns></returns>
        private long GetEndIp()
        {
            this._objfs.Position = this._endIpOff;
            byte[] buff = new Byte[5];
            this._objfs.Read(buff, 0, 5);
            this._endIp = Convert.ToInt64(buff[0]) + Convert.ToInt64(buff[1]) * 256 + Convert.ToInt64(buff[2]) * 256 * 256 + Convert.ToInt64(buff[3]) * 256 * 256 * 256;
            this._countryFlag = buff[4];
            return this._endIp;
        }
        #endregion

        #region 获取国家/区域偏移量
        /// <summary>
        /// 获取国家/区域偏移量
        /// </summary>
        /// <returns></returns>
        private string GetCountry()
        {
            switch (this._countryFlag)
            {
                case 1:
                case 2:
                    Country = GetFlagStr(this._endIpOff + 4);
                    Local = (1 == this._countryFlag) ? " " : GetFlagStr(this._endIpOff + 8);
                    break;
                default:
                    Country = GetFlagStr(this._endIpOff + 4);
                    Local = GetFlagStr(this._objfs.Position);
                    break;
            }
            return " ";
        }
        #endregion

        #region 获取国家/区域字符串
        /// <summary>
        /// 获取国家/区域字符串
        /// </summary>
        /// <param name="offSet"></param>
        /// <returns></returns>
        private string GetFlagStr(long offSet)
        {
            int flag = 0;
            byte[] buff = new Byte[3];
            while (true)
            {
                //objfs.Seek(offSet,SeekOrigin.Begin);
                this._objfs.Position = offSet;
                flag = this._objfs.ReadByte();
                if (flag == 1 || flag == 2)
                {
                    this._objfs.Read(buff, 0, 3);
                    if (flag == 2)
                    {
                        this._countryFlag = 2;
                        this._endIpOff = offSet - 4;
                    }
                    offSet = Convert.ToInt64(buff[0].ToString()) + Convert.ToInt64(buff[1].ToString()) * 256 + Convert.ToInt64(buff[2].ToString()) * 256 * 256;
                }
                else
                {
                    break;
                }
            }
            if (offSet < 12)
                return " ";
            this._objfs.Position = offSet;
            return GetStr();
        }
        #endregion

        #region GetStr
        private string GetStr()
        {
            byte lowC = 0;
            byte upC = 0;
            string str = "";
            byte[] buff = new byte[2];
            while (true)
            {
                lowC = (Byte)this._objfs.ReadByte();
                if (lowC == 0)
                    break;
                if (lowC > 127)
                {
                    upC = (byte)this._objfs.ReadByte();
                    buff[0] = lowC;
                    buff[1] = upC;
                    Encoding enc = Encoding.GetEncoding("GB2312");
                    str += enc.GetString(buff);
                }
                else
                {
                    str += (char)lowC;
                }
            }
            return str;
        }
        #endregion

        #region 获取IP的地理地址
        /// <summary>
        /// 获取IP的地理地址
        /// </summary>
        /// <returns></returns>
        public string IPLocation()
        {
            QQwry();
            return Country + Local.Replace("CZ88.NET", "");//删除垃圾信息
        }
        /// <summary>
        /// 获取IP的地理地址
        /// </summary>
        /// <param name="dataPath"></param>
        /// <param name="ip"></param>
        /// <returns></returns>
        public string IPLocation(string dataPath, string ip)
        {
            DataPath = dataPath;
            IP = ip;
            QQwry();
            return Country + Local.Replace("CZ88.NET", "");//删除垃圾信息
        }
        /// <summary>
        /// 获取IP的地理地址，专门給统计系统用的
        /// </summary>
        /// <param name="strip"></param>
        /// <returns></returns>
        public string IPCountry(string strip)
        {
            IP = strip;
            QQwry();
            return Country;
        }
        public string IPLocal(string strip)
        {
            IP = strip;
            QQwry();

            if (Local == null)
                return "";
            return Local.Replace("CZ88.NET", "");//删除垃圾信息
        }
        #endregion



        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(true);
        }

        /// <summary>
        /// 释放内存
        /// </summary>
        /// <param name="diposing"></param>
        protected void Dispose(bool diposing)
        {
            if (!diposing)
            {
                return;
            }
            if (this._objfs != null)
            {
                this._objfs.Close();
                this._objfs.Dispose();
            }
        }
    }
}